<?php


namespace crack9527\utils\io;


/**
 * Class File
 * @package crack9527\utils\io
 */
class File
{
    /**
     * 完整文件路径
     * @var string
     */
    private $absoluteFilePath = '';
    /**
     * 目录路径
     * @var string
     */
    private $directory = '';
    /**
     * 文件扩展名
     * @var string
     */
    private $extension = '';
    /**
     * 返回文件大小的字节数，如果出错返回 FALSE 并生成一条 E_WARNING 级的错误。
     * @var int
     */
    private $fileSize = 0;
    /**
     * @var bool
     */
    private $isFile = false;
    /**
     * @var bool
     */
    private $isDirectory = false;
    /**
     * 返回路径中的文件名部分
     * @var string
     */
    private $fileName = '';
    /**
     * 返回路径中的文件名+扩展名部分
     * @var string
     */
    private $baseName = '';

    /**
     * File constructor.
     * @param string $fileName
     */
    public function __construct(string $fileName)
    {
        $fileInfo = pathinfo($fileName);
        $fileName = realpath($fileName);
        $this->setFileName($fileInfo['filename']);
        $this->setAbsoluteFilePath($fileName);

        $fileType = filetype($fileName);

        $this->setIsDirectory(is_dir($fileName));
        $this->setIsFile($fileType == 'file' ? true : false);

        if ($this->isFile()) {
            $this->setDirectory(realpath($fileInfo['dirname']));
        } else {
            $this->setDirectory(realpath($fileName));
        }
        $this->setBaseName($fileInfo['basename']);
        if ($this->isFile()) {
            $this->setFileSize(filesize($fileName));
            // 识别扩展名,忽略没有文件名的特殊情况
            $pos = strpos($this->getBaseName(), '.');
            if ($pos > 0) {
                $this->setExtension($fileInfo['extension']);
            }
        }
    }

    /**
     * @return string
     */
    public function getBaseName(): string
    {
        return $this->baseName;
    }

    /**
     * @param string $baseName
     */
    public function setBaseName(string $baseName): void
    {
        $this->baseName = $baseName;
    }

    /**
     * @return string
     */
    public function getAbsoluteFilePath(): string
    {
        return $this->absoluteFilePath;
    }

    /**
     * @param string $absoluteFilePath
     */
    public function setAbsoluteFilePath(string $absoluteFilePath): void
    {
        $this->absoluteFilePath = $absoluteFilePath;
    }

    /**
     * @return string
     */
    public function getDirectory(): string
    {
        return $this->directory;
    }

    /**
     * @param string $directory
     */
    public function setDirectory(string $directory): void
    {
        $this->directory = $directory;
    }

    /**
     * @return string
     */
    public function getExtension(): string
    {
        return $this->extension;
    }

    /**
     * @param string $extension
     */
    public function setExtension(string $extension): void
    {
        $this->extension = $extension;
    }

    /**
     * @return int
     */
    public function getFileSize(): int
    {
        return $this->fileSize;
    }

    /**
     * @param int $fileSize
     */
    public function setFileSize(int $fileSize): void
    {
        $this->fileSize = $fileSize;
    }

    /**
     * @return string
     */
    public function getFileName(): string
    {
        return $this->fileName;
    }

    /**
     * @param string $fileName
     */
    public function setFileName(string $fileName): void
    {
        $this->fileName = $fileName;
    }

    /**
     * @param $group
     * @return bool
     */
    public function chgrp($group)
    {
        return chgrp($this->getAbsoluteFilePath(), $group);
    }

    /**
     * @param $mode
     * @return bool
     */
    public function chmod($mode)
    {
        return chmod($this->getAbsoluteFilePath(), $mode);
    }

    /**
     * @param $user
     * @return bool
     */
    public function chown($user)
    {
        return chown($this->getAbsoluteFilePath(), $user);
    }

    /**
     * @param $dest
     * @return bool
     */
    public function copy($dest)
    {
        $target = new static($dest);
        if ($target->isDirectory()) {
            return copy($this->getAbsoluteFilePath(), $target->getDirectory() . DIRECTORY_SEPARATOR . $this->getBaseName());
        }
        return copy($this->getAbsoluteFilePath(), $dest);
    }

    /**
     * @return bool
     */
    public function delete()
    {
        return unlink($this->getAbsoluteFilePath());
    }

    /**
     * @return bool
     */
    public function exists()
    {
        return file_exists($this->getAbsoluteFilePath());
    }

    /**
     * @return false|string
     */
    public function getContentString()
    {
        return file_get_contents($this->getAbsoluteFilePath());
    }

    /**
     * @param $flags
     * @return array|bool
     * @example
     * 可选参数 flags 可以是以下一个或多个常量：
     * FILE_USE_INCLUDE_PATH 在 include_path 中查找文件。
     * FILE_IGNORE_NEW_LINES 在数组每个元素的末尾不要添加换行符
     * FILE_SKIP_EMPTY_LINES 跳过空行
     */
    public function getContentArray($flags = null)
    {
        return file($this->getAbsoluteFilePath(), $flags);
    }

    /**
     * 取得文件的上次访问时间
     * @return false|int
     */
    public function getAccessTime()
    {
        return fileatime($this->getAbsoluteFilePath());
    }

    /**
     * 取得文件修改时间
     * @return false|int
     */
    public function getModifyTime()
    {
        return filemtime($this->getAbsoluteFilePath());
    }

    /**
     * 取得文件的组
     * @return false|int
     */
    public function getGroup()
    {
        return filegroup($this->getAbsoluteFilePath());
    }

    /**
     * 取得文件的所有者
     * @return false|int
     */
    public function getOwner()
    {
        return fileowner($this->getAbsoluteFilePath());
    }

    /**
     * @return bool
     */
    public function isFile(): bool
    {
        return $this->isFile;
    }

    /**
     * @param bool $isFile
     */
    public function setIsFile(bool $isFile): void
    {
        $this->isFile = $isFile;
    }

    /**
     * @return bool
     */
    public function isDirectory(): bool
    {
        return $this->isDirectory;
    }

    /**
     * @param bool $isDirectory
     */
    public function setIsDirectory(bool $isDirectory): void
    {
        $this->isDirectory = $isDirectory;
    }

    /**
     * @return bool 如果文件存在且可执行则返回 TRUE，错误时返回FALSE。
     */
    public function isExecutable()
    {
        return is_executable($this->getAbsoluteFilePath());
    }

    /**
     * 判断给定文件名是否可读
     * @return bool 如果由指定的文件或目录存在并且可读则返回 TRUE，否则返回 FALSE。
     */
    public function isReadable()
    {
        return is_readable($this->getAbsoluteFilePath());
    }

    /**
     *  判断文件是否是通过 HTTP POST 上传的
     */
    public function isUploadedFile()
    {
        return is_uploaded_file($this->getAbsoluteFilePath());
    }

    /**
     * @return bool 如果文件存在并且可写则返回 TRUE
     */
    public function isWritable()
    {
        return is_writable($this->getAbsoluteFilePath());
    }

    /**
     * 解析一个配置文件
     * @param bool $processSections
     * @param null $scannerMode
     * @return array|bool 成功时以关联数组 array 返回设置,失败时返回 FALSE
     */
    public function parseInIFile($processSections = false, $scannerMode = null)
    {
        return parse_ini_file($this->getAbsoluteFilePath(), $processSections, $scannerMode);
    }

    /**
     * 只修改文件名,不改变文件目录
     * @param string $newName 新文件名称
     * @return bool
     */
    public function rename($newName)
    {
        $target = new static($newName);
        if ($target->isDirectory()) {
            $newName = $target->getBaseName();
        }
        return rename($this->getAbsoluteFilePath(), $this->getDirectory() . DIRECTORY_SEPARATOR . $newName);
    }

    /**
     * 移动文件到指定目录
     * @param string $dest
     * @return bool
     */
    public function move($dest)
    {
        $target = new static($dest);
        if ($target->isDirectory()) {
            return rename($this->getAbsoluteFilePath(), $dest . DIRECTORY_SEPARATOR . $this->getBaseName());
        }
        return rename($this->getAbsoluteFilePath(), $dest);
    }

    public function rmDir()
    {
        if (!$this->exists()) {
            return;
        }
        FileUtils::deleteDirectory($this->getDirectory());
    }

    public function mkdir()
    {
        FileUtils::createDirectory($this->getDirectory());
    }

    /**
     * 计算指定文件的 MD5 散列值
     * @return string
     */
    public function getMd5(): string
    {
        return md5_file($this->getAbsoluteFilePath());
    }

    /**
     *  计算文件的 sha1 散列值
     * @return string
     */
    public function getSHA1()
    {
        return sha1_file($this->getAbsoluteFilePath());
    }
}